home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / elm / elm2.4 / src / editmsg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-08  |  25.7 KB  |  832 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: editmsg.c,v 5.12 1993/05/08 20:25:33 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 5.12 $   $State: Exp $
  6.  *
  7.  *             Copyright (c) 1988-1992 USENET Community Trust
  8.  *            Copyright (c) 1986,1987 Dave Taylor
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log: editmsg.c,v $
  17.  * Revision 5.12  1993/05/08  20:25:33  syd
  18.  * Add sleepmsg to control transient message delays
  19.  * From: Syd
  20.  *
  21.  * Revision 5.11  1993/04/12  03:12:52  syd
  22.  * Added function enforce_newline to enforce newline (what else :-) at
  23.  * end of message.
  24.  * From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
  25.  *
  26.  * Revision 5.10  1993/04/12  01:23:11  syd
  27.  * Fix builtin editor so you can run "readmsg" with "~<".
  28.  * From: chip@chinacat.unicom.com (Chip Rosenthal)
  29.  *
  30.  * Revision 5.9  1993/02/03  17:12:53  syd
  31.  * move more declarations to defs.h, including sleep
  32.  * From: Syd
  33.  *
  34.  * Revision 5.8  1993/01/20  03:37:16  syd
  35.  * Nits and typos in the NLS messages and corresponding default messages.
  36.  * From: dwolfe@pffft.sps.mot.com (Dave Wolfe)
  37.  *
  38.  * Revision 5.7  1992/12/12  01:44:03  syd
  39.  * Fix building editor wrap problem
  40.  * From: Syd via prompting from vogt@isa.de (Gerald Vogt)
  41.  *
  42.  * Revision 5.6  1992/12/11  01:56:11  syd
  43.  * If sigset() and sigrelse() are available, release signal before
  44.  * using longjmp() to leave signal handler.
  45.  * From: chip@tct.com (Chip Salzenberg)
  46.  *
  47.  * Revision 5.5  1992/11/26  00:46:13  syd
  48.  * changes to first change screen back (Raw off) and then issue final
  49.  * error message.
  50.  * From: Syd
  51.  *
  52.  * Revision 5.4  1992/11/22  00:03:28  syd
  53.  * Handle the case where a system does
  54.  * >         #define jmp_buf sigjmp_buf
  55.  * From: chip@chinacat.unicom.com (Chip Rosenthal)
  56.  *
  57.  * Revision 5.3  1992/11/17  04:05:24  syd
  58.  * Fix for editing interrupt broken by posix_signal().
  59.  * From cs.utexas.edu!chinacat!chip Mon Nov 16 09:03:04 1992
  60.  *
  61.  * Revision 5.2  1992/10/17  22:22:33  syd
  62.  * Fix warnings from my ANSI C compiler because the declaration of
  63.  * edit_interrupt did not match the prototype for the second argument of
  64.  * a call to signal.
  65.  * From: Larry Philps <larryp@sco.COM>
  66.  *
  67.  * Revision 5.1  1992/10/03  22:58:40  syd
  68.  * Initial checkin as of 2.4 Release at PL0
  69.  *
  70.  *
  71.  ******************************************************************************/
  72.  
  73. /** This contains routines to do with starting up and using an editor (or two)
  74.     from within Elm.  This stuff used to be in mailmsg2.c...
  75. **/
  76.  
  77. #include "headers.h"
  78. #include "s_elm.h"
  79. #include <errno.h>
  80. #ifndef BSD
  81. /* BSD has already included setjmp.h in headers.h */
  82. #include <setjmp.h>
  83. #endif /* BSD */
  84. #include <ctype.h>
  85.  
  86. #ifdef POSIX_SIGNALS
  87. # define JMP_BUF        sigjmp_buf
  88. # define SETJMP(env)        sigsetjmp((env), 1)
  89. # define LONGJMP(env,val)    siglongjmp((env), (val))
  90. #else
  91. # define JMP_BUF        jmp_buf
  92. # define SETJMP(env)        setjmp(env)
  93. # define LONGJMP(env,val)    longjmp((env), (val))
  94. #endif
  95.  
  96. #ifdef BSD
  97. #undef        tolower
  98. #endif
  99.  
  100. char *error_description(), *format_long(), *strip_commas();
  101. long  fsize();
  102.  
  103. /* The built-in editor is not re-entrant! */
  104. static int    builtin_editor_active = FALSE;
  105. static char *simple_continue = NULL;
  106. static char *post_ed_continue = NULL;
  107.  
  108. extern int errno;
  109. extern char to[VERY_LONG_STRING], cc[VERY_LONG_STRING], 
  110.         expanded_to[VERY_LONG_STRING], expanded_cc[VERY_LONG_STRING], 
  111.         bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING],
  112.         subject[SLEN];
  113.  
  114. int      interrupts_while_editing;    /* keep track 'o dis stuff         */
  115. JMP_BUF  edit_location;            /* for getting back from interrupt */
  116.  
  117. void
  118. tilde_help()
  119. {
  120.     /* a simple routine to print out what is available at this level */
  121.  
  122.     char    buf[SLEN];
  123.  
  124.     Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmEditmsgAvailOpts,
  125.       "\n\r(Available options at this point are:\n\r\n\r"), 0);
  126.     sprintf(buf, catgets(elm_msg_cat, ElmSet, ElmEditmsgHelpMenu,
  127.       "\t%c?\tPrint this help menu.\n\r"), escape_char);
  128.     Write_to_screen(buf, 0);
  129.     if (escape_char == TILDE_ESCAPE) /* doesn't make sense otherwise... */
  130.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmEditmsgAddLine,
  131.           "\t~~\tAdd line prefixed by a single '~' character.\n\r"), 0);
  132.  
  133.     sprintf(buf, catgets(elm_msg_cat, ElmSet, ElmEditmsgBCC,
  134.       "\t%cb\tChange the addresses in the Blind-carbon-copy list.\n\r"),
  135.       escape_char);
  136.     Write_to_screen(buf, 0);
  137.  
  138.     sprintf(buf, catgets(elm_msg_cat, ElmSet, ElmEditmsgCC,
  139.         "\t%cc\tChange the addresses in the Carbon-copy list.\n\r"),
  140.         escape_char);
  141.     Write_to_screen(buf, 0);
  142.     sprintf(buf, catgets(elm_msg_cat, ElmSet, ElmEditmsgEmacs,
  143.           "\t%ce\tInvoke the Emacs editor on the message, if possible.\n\r"),
  144.         escape_char);
  145.     Write_to_screen(buf, 0);
  146.     sprintf(buf, catgets(elm_msg_cat, ElmSet, ElmEditmsgAddMessage,
  147.         "\t%cf\tAdd the specified message or current.\n\r"),
  148.         escape_char);
  149.     Write_to_screen(buf, 0);
  150.     sprintf(buf, catgets(elm_msg_cat, ElmSet, ElmEditmsgToCCBCC,
  151.           "\t%ch\tChange all available headers (to, cc, bcc, subject).\n\r"),
  152.         escape_char);
  153.     Write_to_screen(buf, 0);
  154.     sprintf(buf, catgets(elm_msg_cat, ElmSet, ElmEditmsgSameCurrentPrefix,
  155.         "\t%cm\tSame as '%cf', but with the current 'prefix'.\n\r"),
  156.         escape_char, escape_char);
  157.     Write_to_screen(buf, 0);
  158.     sprintf(buf, catgets(elm_msg_cat, ElmSet, ElmEditmsgUserEditor,
  159.         "\t%co\tInvoke a user specified editor on the message.\n\r"),
  160.         escape_char);
  161.     Write_to_screen(buf, 0);
  162.     sprintf(buf, catgets(elm_msg_cat, ElmSet, ElmEditmsgPrintMsg,
  163.           "\t%cp\tPrint out message as typed in so far.\n\r"), escape_char);
  164.     Write_to_screen(buf, 0);
  165.     sprintf(buf, catgets(elm_msg_cat, ElmSet, ElmEditmsgReadFile,
  166.         "\t%cr\tRead in the specified file.\n\r"), escape_char);
  167.     Write_to_screen(buf, 0);
  168.     sprintf(buf, catgets(elm_msg_cat, ElmSet, ElmEditmsgSubject,
  169.         "\t%cs\tChange the subject of the message.\n\r"), escape_char);
  170.     Write_to_screen(buf, 0);
  171.     sprintf(buf, catgets(elm_msg_cat, ElmSet, ElmEditmsgTo,
  172.         "\t%ct\tChange the addresses in the To list.\n\r"),
  173.         escape_char);
  174.     Write_to_screen(buf, 0);
  175.     sprintf(buf, catgets(elm_msg_cat, ElmSet, ElmEditmsgVi,
  176.         "\t%cv\tInvoke the Vi visual editor on the message.\n\r"),
  177.         escape_char);
  178.     Write_to_screen(buf, 0);
  179.     sprintf(buf, catgets(elm_msg_cat, ElmSet, ElmEditmsgUnixCmd,
  180.       "\t%c!\tExecute a UNIX command (or give a shell if no command).\n\r"),
  181.       escape_char);
  182.     Write_to_screen(buf, 0);
  183.     sprintf(buf, catgets(elm_msg_cat, ElmSet, ElmEditmsgAddUnixCmd,
  184.       "\t%c<\tExecute a UNIX command adding the output to the message.\n\r"),
  185.       escape_char);
  186.     Write_to_screen(buf, 0);
  187.     sprintf(buf, catgets(elm_msg_cat, ElmSet, ElmEditmsgEndMsg,
  188.       "\t.  \tby itself on a line (or a control-D) ends the message.\n\r"));
  189.     Write_to_screen(buf, 0);
  190.     Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmEditmsgContinue,
  191.       "Continue.)\n\r"), 0);
  192. }
  193.  
  194. void
  195. read_in_file(fd, filename, show_user_filename)
  196. FILE *fd;
  197. char *filename;
  198. int   show_user_filename;
  199. {
  200.     /** Open the specified file and stream it in to the already opened 
  201.         file descriptor given to us.  When we're done output the number
  202.         of lines and characters we added, if any... **/
  203.  
  204.     FILE *myfd;
  205.     char myfname[SLEN], buffer[SLEN];
  206.     register int n;
  207.     register int lines = 0, nchars = 0;
  208.  
  209.     for ( n = 0 ; whitespace(filename[n]) ; n++ );
  210.  
  211.     /** expand any shell variables, '~' or other notation... **/
  212.     /* temp copy of filename to buffer since expand_env is destructive */
  213.     strcpy(buffer, &filename[n]);
  214.     expand_env(myfname, buffer);
  215.  
  216.     if (strlen(myfname) == 0) {
  217.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmNoFilenameSpecified,
  218.           "\n\r(No filename specified for file read! Continue.)\n\r"), 0);
  219.       return;
  220.     }
  221.  
  222.     if ((myfd = fopen(myfname,"r")) == NULL) {
  223.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmCouldntReadFile,
  224.         "\n\r(Couldn't read file '%s'! Continue.)\n\r"), 1,
  225.          myfname);
  226.       return;
  227.     }
  228.  
  229.     while (n = mail_gets(buffer, SLEN, myfd)) {
  230.       if(buffer[n-1] == '\n') lines++;
  231.       nchars += n;
  232.         fwrite(buffer, 1, n, fd);
  233.     }
  234.     fflush(fd);
  235.  
  236.     fclose(myfd);
  237.  
  238.     if (lines == 1)
  239.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmAddedLine,
  240.         "\n\r(Added 1 line ["), 0);
  241.     else
  242.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmAddedLinePlural,
  243.         "\n\r(Added %d lines ["), 1, lines);
  244.  
  245.     if (nchars == 1)
  246.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmAddedChar,
  247.         "1 char] "), 0);
  248.     else
  249.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmAddedCharPlural,
  250.         "%d chars] "), 1, nchars);
  251.  
  252.     if (show_user_filename)
  253.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmAddedFromFile,
  254.         "from file %s. Continue.)\n\r"), 1, myfname);
  255.     else
  256.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmAddedToMessage,
  257.         "to message. Continue.)\n\r"), 0);
  258.  
  259.     return;
  260. }
  261.  
  262. void
  263. print_message_so_far(edit_fd, filename)
  264. FILE *edit_fd;
  265. char *filename;
  266. {
  267.     /** This prints out the message typed in so far.  We accomplish
  268.         this in a cheap manner - close the file, reopen it for reading,
  269.         stream it to the screen, then close the file, and reopen it
  270.         for appending.  Simple, but effective!
  271.  
  272.         A nice enhancement would be for this to -> page <- the message
  273.         if it's sufficiently long.  Too much work for now, though.
  274.     **/
  275.     
  276.     char buffer[SLEN];
  277.  
  278.     fflush(edit_fd);
  279.     fseek(edit_fd, 0L, 0);
  280.  
  281.     Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmEditmsgPrintTo,
  282.         "\n\rTo: %s\n\r"), 1, format_long(to, 4));
  283.     Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmEditmsgPrintCC,
  284.         "Cc: %s\n\r"), 1, format_long(cc, 4));
  285.     Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmEditmsgPrintBCC,
  286.         "Bcc: %s\n\r"), 1, format_long(bcc, 5));
  287.     Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmEditmsgPrintSubject,
  288.         "Subject: %s\n\r\n\r"), 1, subject);
  289.  
  290.     while (fgets(buffer, SLEN, edit_fd) != NULL) {
  291.       Write_to_screen(buffer, 0);
  292.       CarriageReturn();
  293.     }
  294.  
  295.     Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmEditmsgPrintContinue,
  296.         "\n\r(Continue entering message.)\n\r"), 0);
  297. }
  298.  
  299. void
  300. read_in_messages(fd, buffer)
  301. FILE *fd;
  302. char *buffer;
  303. {
  304.     /** Read the specified messages into the open file.  If the
  305.         first character of "buffer" is 'm' then prefix it, other-
  306.         wise just stream it in straight...Since we're using the
  307.         pipe to 'readmsg' we can also allow the user to specify
  308.         patterns and such too...
  309.     **/
  310.  
  311.     FILE *myfd, *popen();
  312.     char  local_buffer[SLEN], *arg;
  313.     register int add_prefix=0, mindex;
  314.     register int n;
  315.     int lines = 0, nchars = 0;
  316.  
  317.     add_prefix = tolower(buffer[0]) == 'm';
  318.  
  319.     /* strip whitespace to get argument */
  320.     for(arg = &buffer[1]; whitespace(*arg); arg++)
  321.         ;
  322.  
  323.     /* a couple of quick checks */
  324.     if(message_count < 1) {
  325.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmNoMessageReadContinue,
  326.         "(No messages to read in! Continue.)\n\r"), 0);
  327.       return;
  328.     }
  329.     if (isdigit(*arg)) {
  330.       if((mindex = atoi(arg)) < 1 || mindex > message_count) {
  331.         sprintf(local_buffer, catgets(elm_msg_cat, ElmSet, ElmValidNumbersBetween,
  332.           "(Valid message numbers are between 1 and %d. Continue.)\n\r"),
  333.           message_count);
  334.         Write_to_screen(local_buffer, 0);
  335.         return;
  336.       }
  337.     }
  338.  
  339.     /* dump state information for "readmsg" to use */
  340.     if (create_folder_state_file() != 0)
  341.       return;
  342.  
  343.     /* go run readmsg and get output */
  344.     sprintf(local_buffer, "%s -- %s", readmsg, arg);
  345.     if ((myfd = popen(local_buffer, "r")) == NULL) {
  346.        Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmCantFindReadmsg,
  347.            "(Can't find 'readmsg' command! Continue.)\n\r"),
  348.            0);
  349.        (void) remove_folder_state_file();
  350.        return;    
  351.     }
  352.  
  353.     dprint(5, (debugfile, "** readmsg call: \"%s\" **\n", local_buffer));
  354.  
  355.     while (n = mail_gets(local_buffer, SLEN, myfd)) {
  356.       nchars += n;
  357.       if (local_buffer[n-1] == '\n') lines++;
  358.       if (add_prefix)
  359.         fprintf(fd, "%s", prefixchars);
  360.       fwrite(local_buffer, 1, n, fd);
  361.     }
  362.  
  363.     pclose(myfd);
  364.         (void) remove_folder_state_file();
  365.     
  366.     if (lines == 0) {
  367.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmEditmsgCouldntAdd,
  368.           "(Couldn't add the requested message. Continue.)\n\r"), 0);
  369.       return;
  370.     }
  371.  
  372.     if (lines == 1)
  373.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmAddedLine,
  374.         "\n\r(Added 1 line ["), 0);
  375.     else
  376.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmAddedLinePlural,
  377.         "\n\r(Added %d lines ["), 1, lines);
  378.  
  379.     if (nchars == 1)
  380.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmAddedChar,
  381.         "1 char] "), 0);
  382.     else
  383.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmAddedCharPlural,
  384.         "%d chars] "), 1, nchars);
  385.  
  386.     Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmAddedToMessage,
  387.         "to message. Continue.)\n\r"), 0);
  388.  
  389.     return;
  390. }
  391.  
  392. void
  393. get_with_expansion(prompt, buffer, expanded_buffer, sourcebuf)
  394. char *prompt, *buffer, *expanded_buffer, *sourcebuf;
  395. {
  396.     /** This is used to prompt for a new value of the specified field.
  397.         If expanded_buffer == NULL then we won't bother trying to expand
  398.         this puppy out!  (sourcebuf could be an initial addition)
  399.     **/
  400.  
  401.     Write_to_screen(prompt, 0);    fflush(stdout);    /* output! */
  402.  
  403.     if (sourcebuf != NULL) {
  404.       while (!whitespace(*sourcebuf) && *sourcebuf != '\0') 
  405.         sourcebuf++;
  406.       if (*sourcebuf != '\0') {
  407.         while (whitespace(*sourcebuf)) 
  408.           sourcebuf++;
  409.         if (strlen(sourcebuf) > 0) {
  410.           strcat(buffer, " ");
  411.           strcat(buffer, sourcebuf);
  412.         }
  413.       }
  414.     }
  415.  
  416.     optionally_enter(buffer, -1, -1, TRUE, FALSE);    /* already data! */
  417.  
  418.     if(expanded_buffer != NULL) {
  419.       build_address(strip_commas(buffer), expanded_buffer);
  420.       if(*expanded_buffer != '\0') {
  421.         if (*prompt == '\n')
  422.           Write_to_screen("%s%s", 2, prompt, expanded_buffer);
  423.         else
  424.           Write_to_screen("\n\r%s%s", 2, prompt, expanded_buffer);
  425.       }
  426.     }
  427.     NewLine();
  428.  
  429.     return;
  430. }
  431.  
  432. SIGHAND_TYPE
  433. edit_interrupt(sig)
  434. int sig;
  435. {
  436.     /** This routine is called when the user hits an interrupt key
  437.         while in the builtin editor...it increments the number of 
  438.         times an interrupt is hit and returns it.
  439.     **/
  440.  
  441.     signal(SIGINT, edit_interrupt);
  442.     signal(SIGQUIT, edit_interrupt);
  443.  
  444.     if (interrupts_while_editing++ == 0)
  445.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmEditmsgOneMoreCancel,
  446.         "(Interrupt. One more to cancel this letter.)\n\r"),
  447.           0);
  448.     else
  449.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmEditmsgCancelled,
  450.         "(Interrupt. Letter canceled.)\n\r"), 0);
  451.  
  452. #if defined(SIGSET) && defined(HASSIGHOLD)
  453.     /*
  454.      * During execution of a signal handler set with sigset(),
  455.      * the originating signal is held.  It must be released or
  456.      * it cannot recur.
  457.      */
  458.     sigrelse(sig);
  459. #endif /* SIGSET and HASSIGHOLD */
  460.  
  461.     LONGJMP(edit_location, 1);        /* get back */
  462. }
  463.  
  464. static
  465. enforce_newline(filename)
  466. char *filename;
  467. {
  468.     /** Make sure there is a newline at the end of filename. Mostly to
  469.         be nice to Sun's sendmail, who hangs if there isn't. Return 0
  470.         if something went wrong, 1 otherwise. **/
  471.  
  472.     int err, ch, retcode = 0;
  473.     FILE* fp;
  474.  
  475.     if ((fp = fopen(filename, "r+")) == NULL) {
  476.       err = errno;
  477.       dprint(1, (debugfile, "fopen failed on %s with mode r+\n", filename));
  478.       dprint(1, (debugfile, "** %s **\n", error_description(err)));
  479.     } else if (fseek(fp, -1, 2) == -1) {
  480.       err = errno;
  481.       dprint(1, (debugfile, "fseek(-1,2) failed on %s\n", filename));
  482.       dprint(1, (debugfile, "** %s **\n", error_description(err)));
  483.     } else if ((ch = fgetc(fp)) == EOF) {
  484.       err = errno;
  485.       dprint(1, (debugfile, "unexpected EOF on %s\n", filename));
  486.       if (ferror(fp))
  487.         dprint(1, (debugfile, "** %s **\n", error_description(err)));
  488.     } else if (ch == '\n') {
  489.       retcode = 1;
  490.     } else if (fseek(fp, 0, 2) == -1) {
  491.       err = errno;
  492.       dprint(1, (debugfile, "fseek(0,2) failed on %s\n", filename));
  493.       dprint(1, (debugfile, "** %s **\n", error_description(err)));
  494.       fclose(fp);
  495.     } else if (fputc('\n', fp) == EOF) {
  496.       err = errno;
  497.       dprint(1, (debugfile, "fputc('\\n') failed on %s\n", filename));
  498.       dprint(1, (debugfile, "** %s **\n", error_description(err)));
  499.     } else {
  500.       retcode = 1;
  501.     }
  502.  
  503.     fclose(fp);
  504.     return retcode;
  505. }
  506.  
  507. int
  508. edit_the_message(filename, already_has_text)
  509. char *filename;
  510. int  already_has_text;
  511. {
  512.     /** Invoke the users editor on the filename.  Return when done. 
  513.         If 'already has text' then we can't use the no-editor option
  514.         and must use 'alternative editor' (e.g. $EDITOR or default_editor)
  515.         instead... **/
  516.  
  517.     char buffer[SLEN];
  518.     register int stat, return_value = 0, old_raw;
  519.     int  err;
  520.  
  521.     buffer[0] = '\0';
  522.  
  523.     if (strcmp(editor, "builtin") == 0 || strcmp(editor, "none") == 0) {
  524.       if (already_has_text && strcmp(alternative_editor, "builtin") &&
  525.           strcmp(alternative_editor, "none")) {
  526.         if (in_string(alternative_editor, "%s"))
  527.           sprintf(buffer, alternative_editor, filename);
  528.         else
  529.           sprintf(buffer, "%s %s", alternative_editor, filename);
  530.       } else
  531.         return(no_editor_edit_the_message(filename));
  532.     }
  533.  
  534.     PutLine0(LINES, 0, catgets(elm_msg_cat, ElmSet, ElmInvokeEditor,
  535.       "Invoking editor..."));
  536.     fflush(stdout);
  537.  
  538.     if (strlen(buffer) == 0) {
  539.       if (in_string(editor, "%s"))
  540.         sprintf(buffer, editor, filename);
  541.       else
  542.         sprintf(buffer, "%s %s", editor, filename);
  543.     }
  544.  
  545.     chown(filename, userid, groupid);    /* file was owned by root! */
  546.  
  547.     if (( old_raw = RawState()) == ON)
  548.       Raw(OFF);
  549.  
  550.     if (cursor_control)
  551.       transmit_functions(OFF);        /* function keys are local */
  552.  
  553.     if ((stat = system_call(buffer, SY_ENAB_SIGHUP|SY_DUMPSTATE)) == -1) {
  554.       err = errno;
  555.       dprint(1,(debugfile, 
  556.           "System call failed with stat %d (edit_the_message)\n", 
  557.           stat));
  558.       dprint(1, (debugfile, "** %s **\n", error_description(err)));
  559.       ClearLine(LINES-1);
  560.       error1(catgets(elm_msg_cat, ElmSet, ElmCantInvokeEditor,
  561.         "Can't invoke editor '%s' for composition."), editor);
  562.       if (sleepmsg > 0)
  563.         sleep(sleepmsg);
  564.       return_value = 1;
  565.     }
  566.  
  567.     enforce_newline(filename);
  568.  
  569.     if (old_raw == ON)
  570.        Raw(ON);
  571.  
  572.     SetXYLocation(0, 40);    /* a location not near the next request, so an absolute is used */
  573.     MoveCursor(LINES, 0);    /* dont know where we are, force last row, col 0 */
  574.  
  575.     if (cursor_control)
  576.       transmit_functions(ON);        /* function keys are local */
  577.     
  578.     return(return_value);
  579. }
  580.  
  581. int
  582. no_editor_edit_the_message(filename)
  583. char *filename;
  584. {
  585.     /** If the current editor is set to either "builtin" or "none", then
  586.         invoke this program instead.  As it turns out, this and the 
  587.         routine above have a pretty incestuous relationship (!)...
  588.     **/
  589.  
  590.     FILE *edit_fd;
  591.     char buffer[SLEN], editor_name[SLEN], buf[SLEN], wrap[SLEN];
  592.     int      old_raw, is_wrapped = 0;
  593.     SIGHAND_TYPE    edit_interrupt();
  594.     SIGHAND_TYPE    (*oldint)(), (*oldquit)();
  595.     int  err;
  596.  
  597.     /* The built-in editor is not re-entrant! */
  598.     if (builtin_editor_active) {
  599.       Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmIntReentrantBuiltinEditor,
  600.         "\r\nInternal error - reentrant call to builtin editor attempted.\r\n\r\n"), 0);
  601.       dprint(1, (debugfile,
  602.         "Reentrant call to builtin editor for %s attempted\n", filename));
  603.       return(1);
  604.     }
  605.  
  606.     if (simple_continue == NULL) {
  607.         simple_continue = catgets(elm_msg_cat, ElmSet, ElmSimpleContinue,
  608.           "(Continue.)\n\r");
  609.         post_ed_continue = catgets(elm_msg_cat, ElmSet, ElmPostEdContinue,
  610.           "(Continue entering message.  Type ^D or '.' on a line by itself to end.)\n\r");
  611.     }
  612.  
  613.     if ((edit_fd = fopen(filename, "a+")) == NULL) {
  614.       err = errno;
  615.       sprintf(buffer, catgets(elm_msg_cat, ElmSet, ElmCouldntOpenAppend,
  616.         "Couldn't open %s for appending [%s]."),
  617.         filename, error_description(err));
  618.       Write_to_screen(buffer, 0);
  619.       dprint(1, (debugfile,
  620.         "Error encountered trying to open file %s;\n", filename));
  621.       dprint(1, (debugfile, "** %s **\n", error_description(err)));
  622.       return(1);
  623.     }
  624.  
  625.     /** is there already text in this file? **/
  626.  
  627.     if (fsize(edit_fd) > 0L)
  628.       strcpy(buf, catgets(elm_msg_cat, ElmSet, ElmContinueEntering,
  629.         "\n\rContinue entering message."));
  630.     else
  631.       strcpy(buf, catgets(elm_msg_cat, ElmSet, ElmEnterMessage,
  632.         "\n\rEnter message."));
  633.     strcat(buf, catgets(elm_msg_cat, ElmSet, ElmTypeElmCommands,
  634.       "  Type Elm commands on lines by themselves.\n\r"));
  635.     sprintf(buf + strlen(buf), catgets(elm_msg_cat, ElmSet, ElmCommandsInclude,
  636.     "Commands include:  ^D or '.' to end, %cp to list, %c? for help.\n\r\n\r"),
  637.         escape_char, escape_char);
  638.     CleartoEOS();
  639.     Write_to_screen(buf, 0);
  640.  
  641.     oldint  = signal(SIGINT,  edit_interrupt);
  642.     oldquit = signal(SIGQUIT, edit_interrupt);
  643.  
  644.     builtin_editor_active = TRUE;
  645.     interrupts_while_editing = 0;
  646.  
  647.     if (SETJMP(edit_location) != 0) {
  648.       if (interrupts_while_editing > 1) {
  649.  
  650.         (void) signal(SIGINT,  oldint);
  651.         (void) signal(SIGQUIT, oldquit);
  652.  
  653.         if (edit_fd != NULL)    /* insurance... */
  654.           fclose(edit_fd);
  655.         builtin_editor_active = FALSE;
  656.         return(1);
  657.       }
  658.       goto more_input;    /* read input again, please! */
  659.     }
  660.     
  661. more_input: buffer[0] = '\0';
  662.  
  663. /*** Code changed to provide for line wrapping ***/
  664. wrap_input: wrap[0] = '\0';
  665.  
  666.     while (wrapped_enter(buffer, wrap, -1,-1, edit_fd, &is_wrapped) == 0) {
  667.  
  668.       if (is_wrapped) { /* No need to check for escape or break */
  669.         fprintf(edit_fd, "%s\n", buffer);
  670.         NewLine();
  671.         sprintf(buffer,"%s",wrap);
  672.         goto wrap_input;
  673.       }
  674.  
  675. /*** End of changes for line wrapping ***/
  676.  
  677.       interrupts_while_editing = 0;    /* reset to zero... */
  678.  
  679.       if (strcmp(buffer, ".") == 0)
  680.         break;    /* '.' is as good as a ^D to us dumb programs :-) */
  681.       if (buffer[0] == escape_char) {
  682.         switch (tolower(buffer[1])) {
  683.           case '?' : tilde_help();
  684.              goto more_input;
  685.  
  686.           case TILDE_ESCAPE: move_left(buffer, 1); 
  687.                    goto tilde_input;    /*!!*/
  688.  
  689.           case 't' : get_with_expansion("\n\rTo: ",
  690.                      to, expanded_to, buffer);
  691.              goto more_input;
  692.           case 'b' : get_with_expansion("\n\rBcc: ",
  693.                bcc, expanded_bcc, buffer);
  694.              goto more_input;
  695.           case 'c' : get_with_expansion("\n\rCc: ",
  696.                cc, expanded_cc, buffer);
  697.              goto more_input;
  698.           case 's' : get_with_expansion("\n\rSubject: ",
  699.                subject,NULL,buffer);
  700.                 goto more_input;
  701.  
  702.           case 'h' : get_with_expansion("\n\rTo: ", to, expanded_to, NULL);    
  703.              get_with_expansion("Cc: ", cc, expanded_cc, NULL);
  704.              get_with_expansion("Bcc: ", bcc,expanded_bcc, NULL);
  705.              get_with_expansion("Subject: ", subject, NULL, NULL);
  706.              goto more_input;
  707.  
  708.           case 'r' : read_in_file(edit_fd, (char *) buffer + 2, 1);
  709.                goto more_input;
  710.  
  711.           case 'e' : if (strlen(e_editor) > 0) 
  712.                if (access(e_editor, ACCESS_EXISTS) == 0) {
  713.                  strcpy(buffer, editor);
  714.                  strcpy(editor, e_editor);
  715.                    fclose(edit_fd);
  716.                  (void) edit_the_message(filename,0);
  717.                  strcpy(editor, buffer);
  718.                  edit_fd = fopen(filename, "a+");
  719.                  Write_to_screen(post_ed_continue, 0);
  720.                  goto more_input;
  721.                }
  722.                else
  723.                  Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmCantFindEmacs,
  724.             "\n\r(Can't find Emacs on this system! Continue.)\n\r"),
  725.             0);
  726.              else
  727.                Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmDontKnowEmacs,
  728.             "\n\r(Don't know where Emacs would be. Continue.)\n\r"),
  729.             0);    
  730.              goto more_input;
  731.  
  732.            case 'v' : NewLine();
  733.               strcpy(buffer, editor);
  734.               strcpy(editor, v_editor);
  735.               fclose(edit_fd);
  736.               (void) edit_the_message(filename,0);
  737.               strcpy(editor, buffer);
  738.               edit_fd = fopen(filename, "a+");
  739.               Write_to_screen(post_ed_continue, 0);
  740.               goto more_input;
  741.  
  742.            case 'o' : Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmEnterNameEditor,
  743.                  "\n\rPlease enter the name of the editor: "), 0);
  744.               editor_name[0] = '\0';
  745.               optionally_enter(editor_name,-1,-1, FALSE, FALSE);
  746.               NewLine();
  747.               if (strlen(editor_name) > 0) {
  748.                 strcpy(buffer, editor);
  749.                 strcpy(editor, editor_name);
  750.                 fclose(edit_fd);
  751.                 (void) edit_the_message(filename,0);
  752.                 strcpy(editor, buffer);
  753.                 edit_fd = fopen(filename, "a+");
  754.                 Write_to_screen(post_ed_continue, 0);
  755.                 goto more_input;
  756.               }
  757.                 Write_to_screen(simple_continue, 0);
  758.               goto more_input; 
  759.  
  760.         case '<' : NewLine();
  761.                if (strlen(buffer) < 3)
  762.                  Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmUseSpecificCommand,
  763.          "(You need to use a specific command here. Continue.)\n\r"));
  764.                else {
  765.                  sprintf(buf, " > %s%s.%d 2>&1", temp_dir, temp_edit, getpid());
  766.                  strcat(buffer, buf);
  767.                  if (( old_raw = RawState()) == ON)
  768.                    Raw(OFF);
  769.                  (void) system_call((char *) buffer+2, SY_ENAB_SIGINT|SY_DUMPSTATE);
  770.                  if (old_raw == ON)
  771.                 Raw(ON);
  772.                  sprintf(buffer, "~r %s%s.%d", temp_dir, temp_edit, getpid());
  773.                        read_in_file(edit_fd, (char *) buffer + 3, 0);
  774.                  (void) unlink((char *) buffer+3);
  775.                  SetXYLocation(0, 40);    /* a location not near the next request, so an absolute is used */
  776.                  MoveCursor(LINES, 0);    /* and go to a known location, last row col 0 */
  777.                }
  778.                goto more_input; 
  779.  
  780.         case '!' : NewLine();
  781.                if (( old_raw = RawState()) == ON)
  782.                  Raw(OFF);
  783.                (void) system_call((strlen(buffer) < 3 ? (char *)NULL : buffer+2),
  784.                 SY_USER_SHELL|SY_ENAB_SIGINT|SY_DUMPSTATE);
  785.                if (old_raw == ON)
  786.                   Raw(ON);
  787.                SetXYLocation(0, 40);    /* a location not near the next request, so an absolute is used */
  788.                MoveCursor(LINES, 0);    /* and go to a known location, last row col 0 */
  789.                    Write_to_screen(simple_continue, 0);
  790.                goto more_input;
  791.  
  792.          case 'm' : /* same as 'f' but with leading prefix added */
  793.  
  794.          case 'f' : /* this can be directly translated into a
  795.                    'readmsg' call with the same params! */
  796.                 NewLine();
  797.                 read_in_messages(edit_fd, (char *) buffer + 1);
  798.                 goto more_input;
  799.  
  800.          case 'p' : /* print out message so far.  Soooo simple! */
  801.                 print_message_so_far(edit_fd, filename);
  802.                 goto more_input;
  803.  
  804.          default  : MCsprintf(buf, catgets(elm_msg_cat, ElmSet, ElmDontKnowChar,
  805.              "\n\r(Don't know what %c%c is. Try %c? for help.)\n\r"),
  806.                     escape_char, buffer[1], escape_char);
  807.                 Write_to_screen(buf, 0);
  808.            }
  809.          }
  810.          else {
  811. tilde_input:
  812.            fprintf(edit_fd, "%s\n", buffer);
  813.            NewLine();
  814.          }
  815.       buffer[0] = '\0';
  816.     }
  817.  
  818.  
  819.     Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmEndOfMessage,
  820.       "\n\r<end-of-message>\n\r\n\r\n\r\n\r"), 0);
  821.  
  822.     (void) signal(SIGINT,  oldint);
  823.     (void) signal(SIGQUIT, oldquit);
  824.  
  825.     if (edit_fd != NULL)    /* insurance... */
  826.       fclose(edit_fd);
  827.  
  828.     builtin_editor_active = FALSE;
  829.     return(0);
  830. }
  831.  
  832.